package dao

import (
	"a-common/constant"
	dom "a-common/domain"
	"a-system/domain/entity"
	"strings"
	"sync"

	"xorm.io/xorm"
)

var (
	sysRoleDaoTemp *SysRoleDao
	sysRoleDaoOnce sync.Once
)

type SysRoleDao struct{}

func NewSysRoleDao() *SysRoleDao {
	sysRoleDaoOnce.Do(func() {
		sysRoleDaoTemp = &SysRoleDao{}
	})
	return sysRoleDaoTemp
}

// List 列表
func (m *SysRoleDao) List(args *entity.SysRoleDto, isExport bool) (dom.PageVo, error) {
	// 构建查询条件
	query := pgCli.Table(&entity.SysRole{}).Where("1 = 1")
	if args.Status != "" {
		query.And("status = ?", args.Status)
	}
	if args.Params.BeginTime != "" && args.Params.EndTime != "" {
		query.And("created_at BETWEEN ? AND ?", args.Params.BeginTime, args.Params.EndTime)
	}
	if args.PageNum != 0 && args.PageSize != 0 {
		query.Limit(args.PageSize, (args.PageNum-1)*args.PageSize)
	}
	// 查询
	var vPage dom.PageVo
	if isExport {
		var rows []entity.SysRoleExportVo
		total, err := query.Asc("role_id").FindAndCount(&rows)
		if err != nil {
			return vPage, err
		}
		vPage.Total = total
		vPage.Rows = rows
	} else {
		var rows []entity.SysRolePageVo
		total, err := query.Asc("role_id").FindAndCount(&rows)
		if err != nil {
			return vPage, err
		}
		vPage.Total = total
		vPage.Rows = rows
	}
	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize
	return vPage, nil
}

// ListAll 查询所有
func (m *SysRoleDao) ListAll() ([]entity.SysRoleVo, error) {
	var rows []entity.SysRoleVo
	err := pgCli.Table(&entity.SysRole{}).Where("del_flag = ?", constant.ROLE_NORMAL).Asc("role_sort").Find(&rows)
	if err != nil {
		return rows, err
	}
	return rows, nil
}

// Get 查
func (m *SysRoleDao) Get(id string) (entity.SysRolePageVo, error) {
	var v entity.SysRolePageVo
	_, err := pgCli.Table(&entity.SysRole{}).ID(id).Get(&v)
	return v, err
}

// Add 增
func (m *SysRoleDao) Add(args *entity.SysRoleDto) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}

	sysRole := entity.SysRole{
		Status: args.Status,
		BaseStruct: dom.BaseStruct{
			CreatedBy: args.CreatedBy,
			UpdatedBy: args.CreatedBy,
			Remark:    args.Remark,
		},
	}
	// 更新角色信息
	if _, err := session.Insert(&sysRole); err != nil {
		return err
	}

	// 更新角色权限菜单信息
	if _, err := session.Where("role_id = ?", sysRole.RoleId).Unscoped().Delete(&entity.SysRoleMenu{}); err != nil {
		return err
	}
	var roleMenus []entity.SysRoleMenu
	if _, err := session.Insert(&roleMenus); err != nil {
		return err
	}
	return session.Commit()
}

// Edit 改
func (m *SysRoleDao) Edit(args *entity.SysRoleDto) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}

	// 更新角色信息
	if _, err := session.ID(args.RoleId).Update(&entity.SysRole{
		Status: args.Status,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: args.UpdatedBy,
			Remark:    args.Remark,
		},
	}); err != nil {
		return err
	}

	// 更新角色权限菜单信息
	if _, err := session.Where("role_id = ?", args.RoleId).Unscoped().Delete(&entity.SysRoleMenu{}); err != nil {
		return err
	}
	var roleMenus []entity.SysRoleMenu
	if _, err := session.Insert(&roleMenus); err != nil {
		return err
	}
	return session.Commit()
}

// Del 删
func (m *SysRoleDao) Del(ids string) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}
	var roleIds = strings.Split(ids, `,`)
	if _, err := session.In("role_id", roleIds).Unscoped().Delete(&entity.SysRole{}); err != nil {
		return err
	}
	if _, err := session.In("role_id", roleIds).Unscoped().Delete(&entity.SysRoleMenu{}); err != nil {
		return err
	}
	return session.Commit()
}

// AuthDataScope 修改数据权限信息
func (m *SysRoleDao) AuthDataScope(args *entity.SysRoleDto) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}

	// 更新角色信息
	if _, err := session.ID(args.RoleId).Update(&entity.SysRole{
		Status: args.Status,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: args.UpdatedBy,
			Remark:    args.Remark,
		},
	}); err != nil {
		return err
	}

	// 更新角色权限菜单信息
	if _, err := session.Where("role_id = ?", args.RoleId).Unscoped().Delete(&entity.SysRoleDept{}); err != nil {
		return err
	}
	return session.Commit()
}

// CheckRoleNameUnique 校验角色名称是否唯一
func (m *SysRoleDao) CheckRoleNameUnique(roleName string, roleId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if roleId != 0 {
		query.And("role_id != ?", roleId)
	}
	return query.Exist(&entity.SysRole{})
}

// CheckRoleKeyUnique 校验角色权限标识符是否唯一
func (m *SysRoleDao) CheckRoleKeyUnique(roleKey string, roleId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if roleId != 0 {
		query.And("role_id != ?", roleId)
	}
	return query.Exist(&entity.SysRole{})
}

// ChangeStatus 切换状态
func (m *SysRoleDao) ChangeStatus(roleId string, status string) (int64, error) {
	return pgCli.ID(roleId).Update(&entity.SysRole{
		Status: status,
	})
}

// GetRoleByUserId 通过userId获取角色信息
func (m *SysRoleDao) GetRoleByUserId(userId int64) ([]entity.SysRoleVo, error) {
	var v []entity.SysRoleVo
	// 嵌套查询
	// err := pgCli.Table(&entity.SysRole{}).In("role_id", builder.Select("role_id").From("sys_user_role").Where(builder.Eq{"user_id": userId})).Find(&v)
	err := pgCli.Table("sys_user_role").Join(
		"left",
		"sys_role",
		"sys_role.role_id = sys_user_role.role_id").Where("sys_user_role.user_id = ?", userId).Find(&v)
	return v, err
}

// GetMenuIdsByRoleIds 根据角色Id获取角色拥有的菜单Id
func (m *SysRoleDao) GetMenuIdsByRoleIds(roleIds []string) ([]uint, error) {
	var mIds []uint
	err := pgCli.Table(&entity.SysRoleMenu{}).Select("id").Where("role_id IN (?)", roleIds).Find(&mIds)
	return mIds, err
}

// GetDeptIdsByRoleIds 根据角色Id获取角色拥有的部门Id
func (m *SysRoleDao) GetDeptIdsByRoleIds(roleIds []string) ([]uint, error) {
	var dIds []uint
	err := pgCli.Table(&entity.SysRoleDept{}).Select("dept_id").Where("role_id IN (?)", roleIds).Find(&dIds)
	return dIds, err
}

// UpdateRoleMenu 更新角色菜单
func (m *SysRoleDao) UpdateRoleMenu(args entity.SysRoleDto, menuIds []int64) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}

	// 更新角色信息
	if _, err := session.ID(args.RoleId).Update(&entity.SysRole{
		Status: args.Status,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: args.UpdatedBy,
			Remark:    args.Remark,
		},
	}); err != nil {
		return err
	}

	// 更新角色权限菜单信息
	if _, err := session.Where("role_id = ?", args.RoleId).Unscoped().Delete(&entity.SysRoleMenu{}); err != nil {
		return err
	}
	var roleMenus []entity.SysRoleMenu
	for _, item := range menuIds {
		roleMenus = append(roleMenus, entity.SysRoleMenu{RoleId: args.RoleId, MenuId: item})
	}
	if _, err := session.Insert(&roleMenus); err != nil {
		return err
	}
	return session.Commit()
}

// UpdateRoleDept 更新角色部门
func (m *SysRoleDao) UpdateRoleDept(roleId int64, deptIds []int64) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	// add Begin() before any action
	if err := session.Begin(); err != nil {
		return err
	}

	var roleDepts []entity.SysRoleDept
	for _, item := range deptIds {
		roleDepts = append(roleDepts, entity.SysRoleDept{RoleID: roleId, DeptId: item})
	}
	if _, err := session.Insert(&roleDepts); err != nil {
		return err
	}

	// add Commit() after all actions
	return session.Commit()
}

// InsertAuthUsers 批量选择授权用户角色
func (m *SysRoleDao) InsertAuthUsers(roleId int64, userIds []int64) error {
	session := pgCli.NewSession()
	defer func(session *xorm.Session) {
		_ = session.Close()
	}(session)
	if err := session.Begin(); err != nil {
		return err
	}

	var userRoles []entity.SysUserRole
	for _, item := range userIds {
		userRoles = append(userRoles, entity.SysUserRole{RoleId: roleId, UserId: item})
	}
	if _, err := session.Insert(&userRoles); err != nil {
		return err
	}

	return session.Commit()
}

// DeleteAuthUser 取消授权用户角色
func (m *SysRoleDao) DeleteAuthUser(roleId int64, userId int64) (int64, error) {
	return pgCli.Table(&entity.SysUserRole{}).Where("role_id = ?", roleId).And("user_id = ?", userId).Unscoped().Delete()
}

// DeleteAuthUsers 批量取消授权用户
func (m *SysRoleDao) DeleteAuthUsers(roleId int64, userIds []int64) (int64, error) {
	return pgCli.Table(&entity.SysUserRole{}).Where("role_id = ?", roleId).In("user_id", userIds).Unscoped().Delete()
}

// GetAllRoleMenu 获取所有角色及对应的权限
func (m *SysRoleDao) GetAllRoleMenu() ([]any, error) {
	var v []any
	return v, nil
}
